import { WASM_FILE_NAME } from "./entities/const";
import * as vscode from "vscode";
import * as path from "path";
import { DefinitionInfo } from "./entities/types";
import { Logger } from '../../src/logger/Logger';
import { initParser } from "../workspace_api";

// 导入 TreeSitter 类型
type Point = { row: number; column: number };
// 注意: web-tree-sitter 的类型定义有问题，使用 any 作为临时解决方案
type SyntaxNode = any;
type Parser = any;

interface NodeType {
  name: string,
  text: string,
  type: string,
  signature: string,
  range: vscode.Range
}

interface ASTContext {
  functionTypes: NodeType[],
}

function asPosition(point: Point): vscode.Position {
  return new vscode.Position(point.row, point.column);
}

export class TreeSitter implements vscode.Disposable {
  private wasmFilePath = '';
  private functionRangeCaches = new Map<string, vscode.Range[]>();
  private parsers: Map<string, any> = new Map();
  private disposes: vscode.Disposable[] = [];
  private static _instance: TreeSitter;
  private cacheMap: Map<string, Map<string, DefinitionInfo>> = new Map(); // 缓存的Map，外层键为文档的uri，内层Map存储名称到范围的映射
  private context: ASTContext = { functionTypes: [] };
  private basicTypes = new Set(['string', 'int', 'float', 'double', 'char', 'bool', 'void', 'short', 'long', 'unsigned', 'signed']);

  private constructor() {
    this.disposes.push(
      vscode.workspace.onDidChangeTextDocument((e: any) => {
        this.updatefunctionRangeCache(e.document);
      })
    );
  }

  public dispose() {
    this.disposes.map((e) => e.dispose());
  }

  public static getInstance(): TreeSitter {
    if (!this._instance) {
      this._instance = new TreeSitter();
    }
    return this._instance;
  }

  public async init(): Promise<void> {
    if(!this.parsers.get("c")) {
      const parserC = await initParser(WASM_FILE_NAME["c"]);
      this.parsers.set("c", parserC);
    }
    if(!this.parsers.get("cpp")) {
      const parserCPP = await initParser(WASM_FILE_NAME["cpp"]);
      this.parsers.set("cpp", parserCPP);
    }
  }

  public getTree(code: string, language: string): any {
    // 标准化语言 ID：C++ 可能被识别为 'cpp', 'c++', 或 'cplusplus'
    let normalizedLang = language.toLowerCase();
    if (normalizedLang === 'c++' || normalizedLang === 'cplusplus') {
      normalizedLang = 'cpp';
    }
    
    const parser = this.parsers.get(normalizedLang);
    if (parser) {
      return parser.parse(code);
    }
    
    Logger.warn(`[getTree] 未找到解析器: ${language} (normalized: ${normalizedLang}), 可用: ${Array.from(this.parsers.keys()).join(', ')}`);
    return null;
  }

  public getPublicParser(language: string): any | null {
    // 标准化语言 ID
    let normalizedLang = language.toLowerCase();
    if (normalizedLang === 'c++' || normalizedLang === 'cplusplus') {
      normalizedLang = 'cpp';
    }
    
    const parser = this.parsers.get(normalizedLang);
    if (parser) {
      return parser;
    }
    return null;
  }

  /**
   * 清除缓存
   */
  public clearCache() {
    this.cacheMap.clear();
  }

  public getFunctionRangeFromCache(doc: vscode.TextDocument) {
    const filePath = doc.uri.fsPath;
    const functionRange = this.functionRangeCaches.get(filePath);
    if (functionRange?.length) {
      return functionRange;
    }
    const results = TreeSitter.getInstance().getFunctionRange(doc.getText(), doc.languageId);
    if (results) {
      this.functionRangeCaches.set(filePath, results);
    }
    return results;
  }

  /**
   * 解析文档并缓存其中类、结构体、枚举的定义代码中名称到范围的映射到Map中
   * @param location VSCode 位置信息
   */
  public async cacheCodeRanges(location: vscode.Location): Promise<void> {
    try {
      const document = await vscode.workspace.openTextDocument(location.uri);
      const code = document.getText();
      
      // 标准化语言 ID
      let normalizedLang = document.languageId.toLowerCase();
      if (normalizedLang === 'c++' || normalizedLang === 'cplusplus') {
        normalizedLang = 'cpp';
      }
      
      const parser = this.parsers.get(normalizedLang);
      if (!parser) {
        Logger.warn(`[cacheCodeRanges] 未找到解析器: ${document.languageId} (normalized: ${normalizedLang})`);
        return;
      }
      const tree = parser.parse(code);

      const queryStr = `
            (class_specifier
                name: (type_identifier) @name
            ) @class_whole
            (struct_specifier
                name: (type_identifier) @name
            ) @struct_whole
            (enum_specifier
                name: (type_identifier) @name
            ) @enum_whole
            (function_definition type: 
                (class_specifier 
                    name: (type_identifier)
                ) declarator: (identifier) @name 
            ) @class_whole
        `;
      const query = parser.getLanguage().query(queryStr);
      const captures = query.captures(tree.rootNode);
      for (const capture of captures) {
        if (capture.name === "name") {
          const associatedWholeCapture = captures.find((c: any) => c.name.endsWith("_whole") && c.node.startIndex <= capture.node.startIndex && c.node.endIndex >= capture.node.endIndex);
          if (associatedWholeCapture) {
            const startPosition = document.positionAt(associatedWholeCapture.node.startIndex);
            const endPosition = document.positionAt(associatedWholeCapture.node.endIndex);
            const foundRange = new vscode.Range(startPosition.line, startPosition.character, endPosition.line, endPosition.character);
            const name = capture.node.text;
            this.cacheDefinition(document, name, {
              range: foundRange,
              type: associatedWholeCapture.name.replace(/_whole$/, ""),
              name,
              document,
            });
          }
        }
      }
    } catch (error) {
      Logger.error(`Error caching code ranges: ${error}`);
    }
  }

  public getCacheMapByUriStr(uriStr: string) {
    return this.cacheMap.get(uriStr);
  }

  /**
   * 缓存定义信息
   */
  private cacheDefinition(document: vscode.TextDocument, name: string, info: DefinitionInfo) {
    const uri = document.uri.toString();
    if (!this.cacheMap.has(uri)) {
      this.cacheMap.set(uri, new Map());
    }
    this.cacheMap.get(uri)?.set(name, info);
  }

  /**
   * 获取缓存的定义信息
   */
  public getCachedDefinition(document: vscode.TextDocument, name: string): DefinitionInfo | undefined {
    return this.cacheMap.get(document.uri.toString())?.get(name);
  }
  public setWasmFilePath(path:string) {
    this.wasmFilePath = path;
  }

  private getFunctionRange(code: string, languageId?: string): vscode.Range[] {
    Logger.info(`[getFunctionRange] 开始解析，代码长度: ${code.length}, languageId: ${languageId}`);
    const parser = this.getParser(languageId);
    Logger.info(`[getFunctionRange] getParser(${languageId}) 返回: ${parser ? '有效' : 'null'}`);
    
    if (parser) {
      const tree = parser.parse(code);
      Logger.info(`[getFunctionRange] tree.rootNode: ${tree.rootNode ? '有效' : 'null'}, type: ${tree.rootNode?.type}`);
      
      const functionRanges = this.getChildFunction(tree.rootNode);
      Logger.info(`[getFunctionRange] getChildFunction 返回: ${functionRanges.length} 个函数`);
      
      return functionRanges;
    }
    
    Logger.warn(`[getFunctionRange] parser 为 null，返回空数组`);
    return [];
  }

  private getParser(languageId?: string): any | undefined {
    // 如果提供了 languageId，标准化并使用它
    if (languageId) {
      // 标准化语言 ID：C++ 可能被识别为 'cpp', 'c++', 或 'cplusplus'
      let normalizedLang = languageId.toLowerCase();
      if (normalizedLang === 'c++' || normalizedLang === 'cplusplus') {
        normalizedLang = 'cpp';
      }
      
      const parser = this.parsers.get(normalizedLang);
      Logger.info(`[getParser] 使用提供的 languageId: ${languageId} (normalized: ${normalizedLang}), parser: ${parser ? '有效' : 'null'}`);
      Logger.info(`[getParser] 可用的 parsers: ${Array.from(this.parsers.keys()).join(', ')}`);
      return parser;
    }
    
    // 否则尝试从活动编辑器获取
    const activeEditor = vscode.window.activeTextEditor;
    if (activeEditor) {
      Logger.info(`[getParser] 从活动编辑器获取 languageId: ${activeEditor.document.languageId}`);
      
      // 标准化语言 ID
      let normalizedLang = activeEditor.document.languageId.toLowerCase();
      if (normalizedLang === 'c++' || normalizedLang === 'cplusplus') {
        normalizedLang = 'cpp';
      }
      
      return this.parsers.get(normalizedLang);
    }
    
    Logger.warn(`[getParser] 没有提供 languageId 且没有活动编辑器`);
    return undefined;
  }

  private getChildFunction(node: any): vscode.Range[] {
    const functionSymbols: vscode.Range[] = [];
    const stack: any[] = [node];
    while (stack.length > 0) {
      const currentNode = stack.pop();
      if (currentNode.type === "function_definition") {
        functionSymbols.push(
          new vscode.Range(new vscode.Position(currentNode.startPosition.row, currentNode.startPosition.column), new vscode.Position(currentNode.endPosition.row, currentNode.endPosition.column))
        );
      }
      for (let i = currentNode.childCount - 1; i >= 0; i--) {
        stack.push(currentNode.child(i));
      }
    }
    return functionSymbols;
  }

  private updatefunctionRangeCache(doc: vscode.TextDocument | undefined) {
    if (doc && (doc.languageId === "cpp" || doc.languageId === "c")) {
      const functionRange = TreeSitter.getInstance().getFunctionRange(doc.getText(), doc.languageId);
      if (functionRange) {
        this.functionRangeCaches.set(doc.uri.fsPath, functionRange);
      }
    }
  }

  public getFirstClassSpecifier(text: string, language: string): string[] {
    // 标准化语言 ID
    let normalizedLang = language.toLowerCase();
    if (normalizedLang === 'c++' || normalizedLang === 'cplusplus') {
      normalizedLang = 'cpp';
    }
    
    const parser = this.parsers.get(normalizedLang);
    let classSpecifier: string[] = [];
    if (parser) {
        try {
            const tree = parser.parse(text);
            classSpecifier = this.getTargetNodeText(tree.rootNode, ['class_specifier']);
        } catch (error: any) {
          Logger.error(`getFisrtclassSpecifier cache failed. error: ${error?.message}`);
        }
    }
    return classSpecifier;
  }

  public getTargetNodeText(node: SyntaxNode, nodeType: string[]): string[] {
    const nodeTextSet: Set<string> = new Set<string>();
    const stack: SyntaxNode[] = [node];
    while (stack.length > 0) {
      const currentNode = stack.pop();
      if (!currentNode) {
        continue;
      }
      if (currentNode && nodeType.includes(currentNode.type)) {
        nodeTextSet.add(currentNode.text);
      }
      for (let i = currentNode.childCount - 1; i >= 0; i--) {
        stack.push(currentNode.child(i) as SyntaxNode);
      }
    }
    return Array.from(nodeTextSet);
  }

  public async getFunctionTypes(doc: vscode.TextDocument, update = false): Promise<NodeType[]> {
    let functionTypes = this.context.functionTypes;
    if (!functionTypes.length || update) {
      await this.updateContext(doc);
      functionTypes = this.context.functionTypes;
    }

    return functionTypes;
  }

  public async updateContext(doc: vscode.TextDocument) {
    try {
      // 确保 TreeSitter 已初始化
      await this.init();
      
      const tree = this.getTree(doc.getText(), doc.languageId);
      
      if (!tree) {
        Logger.error(`[updateContext] 无法获取语法树，languageId: ${doc.languageId}`);
        return;
      }
      
      this.traverseNode(tree?.rootNode);
    } catch (error) {
      Logger.error(`Error while updateContext: ${error}`);
    }

  }

  public traverseNode(node: SyntaxNode | null | undefined) {
    this.context = { functionTypes: [] };
    const functionTypes = node?.descendantsOfType('function_definition');
    functionTypes?.forEach((e: any) => this.visitFunctionDecl(e));
  }

  private visitFunctionDecl(node: SyntaxNode) {
    const { startPosition, endPosition, text, type } = node;
    const name = node.descendantsOfType('function_declarator')[0]?.childForFieldName('declarator')?.text ?? '';
    if (!name) {
      return;
    }
    const returnType = node.childForFieldName('type')?.text ?? '';
    const signature = node.childForFieldName('declarator')?.text ?? '';
    this.context.functionTypes.push({
      name,
      text,
      type,
      signature: `${returnType} ${signature}`.trim(),
      range: new vscode.Range(asPosition(startPosition), asPosition(endPosition))
    });
  }

  public async getSymbols(languageId: string, code: string): Promise<string[]> {
    // 确保 TreeSitter 已初始化
    await this.init();
    
    const tree = this.getTree(code, languageId);
    const symbols: string[] = [];
    if (tree) {
      const funcDeclSymbols = this.getFuncDeclSymbols(tree.rootNode);
      const identifierTypes = this.getIdentifierTypes(tree.rootNode);

      identifierTypes.forEach((item) => {
        if (!funcDeclSymbols.includes(item.text) && !symbols.includes(item.text)) {
          symbols.push(item.text);
        }
      });
    } else {
      Logger.warn(`[getSymbols] 无法获取语法树，languageId: ${languageId}`);
    }

    return symbols;
  }


  private getFuncDeclSymbols(node: SyntaxNode) {
    const symbols: string[] = [];
    const declarationTypes = this.getDeclarationTypes(node);

    declarationTypes.forEach((item) => {
      let text = (item.text).replace(';', '');
      if (text.includes('=')) {
        text = text.split('=')[0];
      }
      const symbol = text.trim().split(' ').pop()?.replace('*', '') || '';
      if (!symbols.includes(symbol)) {
        symbols.push(symbol);
      }
    });

    return symbols;
  }

  private getDeclarationTypes(node: SyntaxNode) {
    const declarationTypes = [
      ...node?.descendantsOfType('declaration'),
      ...node?.descendantsOfType('parameter_declaration')
    ];

    return declarationTypes;
  }

  private getIdentifierTypes(node: SyntaxNode) {
    const identifierTypes = [
      ...node?.descendantsOfType('identifier'),
      ...node?.descendantsOfType('type_identifier'),
      ...node?.descendantsOfType('field_identifier'),
      ...node?.descendantsOfType('namespace_identifier')
    ];

    return identifierTypes;
  }

  public getTargetNode(node: SyntaxNode, nodeType: string[]): SyntaxNode[] {
    const stack: SyntaxNode[] = [node];
    const nodeSet: Set<SyntaxNode> = new Set<SyntaxNode>();
    while (stack.length > 0) {
      const currentNode = stack.pop();
      if (!currentNode) {
        continue;
      }
      if (currentNode && nodeType.includes(currentNode.type)) {
        nodeSet.add(currentNode);
      }
      for (let i = currentNode.childCount - 1; i >= 0; i--) {
        stack.push(currentNode.child(i) as SyntaxNode);
      }
    }
    return Array.from(nodeSet);
  }

  public getSourceClassName(node: SyntaxNode): string | undefined {
    const functionDefinition = node.descendantsOfType('function_declarator');
    for (const func of functionDefinition) {
      const res = func.childForFieldName('declarator')?.descendantsOfType('namespace_identifier');
      if (res?.length) {
        return res[res.length - 1].text;
      }
    }
    return undefined;
  }

  private isBasicType(type: string): boolean {
    const lowerCaseType = type.toLowerCase();
    return Array.from(this.basicTypes).some(basicType => basicType.toLowerCase() === lowerCaseType);
  }

  /**
       * 根据名称查找定义位置的通用方法
       * @param document 当前文档
       * @param name 要查找的名称（类名、返回值类型等）
       * @param functionRange 可选的搜索范围，优先在此范围内匹配
       * @returns Promise<vscode.Location | null>
       */
  public async findDefinitionPositionByName(
    document: vscode.TextDocument,
    name: string,
    functionRange?: vscode.Range
  ): Promise<vscode.Location | null> {
    const text = document.getText();

    // 创建正则表达式，确保name前后不是字母、数字、下划线
    // 并排除注释行
    const nameRegex = new RegExp(
      `(?<![\\w])${this.escapeRegExp(name)}(?![\\w])`,
      'g'
    );

    // 如果提供了functionRange，先在指定范围内搜索
    if (functionRange) {
      const rangeText = document.getText(functionRange);
      const rangeRegex = new RegExp(
        `(?<![\\w])${this.escapeRegExp(name)}(?![\\w])`,
        'g'
      );

      let match: RegExpExecArray | null;
      while ((match = rangeRegex.exec(rangeText)) !== null) {
        const matchIndex = functionRange.start.character + match.index;
        const position = document.positionAt(
          document.offsetAt(functionRange.start) + match.index
        );

        // 获取匹配所在的行
        const line = document.lineAt(position);

        // 检查是否为注释行
        const trimmedLine = line.text.trim();
        if (this.isCommentLine(trimmedLine)) {
          return await this.resolveDefinition(document, position);
        }
      }
    }

    // 如果在functionRange中未找到，则在全文中搜索
    let match: RegExpExecArray | null;
    while ((match = nameRegex.exec(text)) !== null) {
      const matchIndex = match.index;
      const position = document.positionAt(matchIndex);

      // 获取匹配所在的行
      const line = document.lineAt(position);

      // 检查是否为注释行
      const trimmedLine = line.text.trim();
      if (this.isCommentLine(trimmedLine)) {
        return await this.resolveDefinition(document, position);
      }
    }

    return null;
  }

  private isCommentLine(line:string):boolean{
    return !line.startsWith('//') && !line.startsWith('*') &&!line.startsWith('/*');
  }

  /**
 * 快捷方法：根据名称获取完整代码块
 * @param document 文档
 * @param name 名称
 * @param functionRange 指定的范围
 * @returns Promise<string>
 */
  public async getFullDefinitionByName(
    document: vscode.TextDocument,
    typeName: string,
    functionRange: vscode.Range
  ): Promise<DefinitionInfo | undefined> {
    try {
      if (this.isBasicType(typeName)) {
        return undefined;
      }
      // 查找定义位置
      const definitionLocation = await this.findDefinitionPositionByName(document, typeName, functionRange);

      if (!definitionLocation) {
        Logger.info(`${typeName} not found`);
        return undefined;
      }

      // 获取完整代码
      return await this.getCodeAtLocation(definitionLocation, typeName);
    } catch (error) {
      Logger.error(`Error getting definition for ${typeName}: ${error}`);
      return undefined;
    }
  }

  /**
    * 根据名称获取对应代码文本（会先尝试从缓存中查找范围）
    * @param location VSCode 位置信息
    * @param name 要查找的名称（类名、结构体名、枚举名等）
    * @returns Promise<string>
    */
  public async getCodeAtLocation(location: vscode.Location, name: string): Promise<DefinitionInfo | undefined> {
    try {
      const document = await vscode.workspace.openTextDocument(location.uri);
      const uriStr = location.uri.toString();
      let uriMap = this.cacheMap.get(uriStr);
      if (!uriMap) {
        await this.cacheCodeRanges(location);
        uriMap = this.cacheMap.get(uriStr);
      }
      if (uriMap && uriMap.has(name)) {
        const cached = this.getCachedDefinition(document, name);
        return cached;
      }
      return undefined;
    } catch (error) {
      Logger.error(`Error retrieving code at location: ${error}` );
      return undefined;
    }
  }

  /**
       * 解析定义的内部方法（可以根据需要缓存）
       * @param document 文档
       * @param position 位置
       * @returns Promise<vscode.Location | null>
       */
  public async resolveDefinition(
    document: vscode.TextDocument,
    position: vscode.Position
  ): Promise<vscode.Location | null> {
    try {

      const editor = vscode.window.activeTextEditor;
      if (editor && editor.selection.contains(position)) {
        // 如果当前位置在选中区域内，尝试取消选中
        editor.selection = new vscode.Selection(position, position);
      }
      const definitions = await vscode.commands.executeCommand<vscode.Location[]>(
        'vscode.executeDefinitionProvider',
        document.uri,
        position
      );

      if (!definitions || definitions.length < 1) {
        return null;
      }
      const firstDefinition = definitions[0];
      // 检查 definitions[0] 的 uri 中的文件名是否是 C++ 标准库文件名
      if (this.isStandardLibrary(firstDefinition.uri)) {
        return null;
      }
      return firstDefinition;
    } catch (error) {
      Logger.error(`Definition resolution error: ${error}`);
      return null;
    }
  }

  /**
   * 判断给定的URI是否是C++标准库文件：如果目标文件不在项目路径下则视为C++标准库文件
   * @param uri 文件URI
   * @returns boolean
   */
  private isStandardLibrary(uri: vscode.Uri): boolean {
    const uriPath = uri.path
    const projectPath = this.getCurrentProjectPath();
    if (!projectPath) {
      return false;
    }
    return !uriPath.startsWith(projectPath);
  }

  /**
 * 获取当前项目名称
 * @returns 当前项目名
 */
  private getCurrentProjectPath(): string | null {
    const workspaceFolders = vscode.workspace.workspaceFolders;
    return (workspaceFolders && workspaceFolders.length > 0) ? workspaceFolders[0].uri.path : null
  }

  /**
   * 转义正则表达式特殊字符
   * @param string 待转义的字符串
   * @returns 转义后的字符串
   */
  private escapeRegExp(string: string): string {
    return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }
}